#include "GameApplication.h"
#include "UpdateTask.h"

GameApplication::GameApplication()
{
	m_selectables = new System();
	m_selectables->Initialize();
}

// Entity Groups

std::list<Entity*>& GameApplication::getEntityGroup( HashedString name )
{
	return m_entityGroups[name];
}
void GameApplication::RegisterEntityToGroup( HashedString name, Entity* entity )
{
	m_entityGroups[name].push_back(entity);
}
void GameApplication::RemoveEntityFromGroups( Entity* entity )
{

	for (std::map<HashedString, std::list<Entity*>>::iterator group = m_entityGroups.begin(); group != m_entityGroups.end(); ++group)
	{
		std::list<Entity*>& entities = group->second;
		for (std::list<Entity*>::iterator entityList = entities.begin(); entityList != entities.end(); ++entityList)
		{
			if (*entityList == entity)
			{
				entities.erase(entityList);
				break;
			}
		}
	}
}

// Entity
void GameApplication::RegisterEntity( HashedString name, Pointer<Entity> entity )
{
	m_entities.insert(Entity::Pair_t(name, entity));
}
Pointer<Entity> GameApplication::RetrieveEntity( HashedString name )
{
	Pointer<Entity> entity;
	Entity::Map_t::iterator it = m_entities.find(name);
	if (it != m_entities.end())
		entity = it->second;
	return entity;	
}
void GameApplication::RemoveEntity( HashedString name )
{
	Entity::Map_t::iterator it = m_entities.find(name);
	if (it == m_entities.end())
		return;

	for (IEntityController::Vector_t::iterator it1 = m_controllers.begin(); it1 != m_controllers.end(); ++it1)
	{
		if ((Entity*)((*it1)->getEntity()) == (it->second))
		{
			UpdateTask::getSingleton().RemoveUpdateable(*it1);
			m_controllers.erase(it1);
			break;
		}
	}

	m_entities.erase(it);
}
void GameApplication::RemoveEntity( Entity* entity )
{
	for (Entity::Map_t::iterator it = m_entities.begin(); it != m_entities.end(); ++it)
	{
		if ((Entity*)(it->second) == entity)
		{
			m_entities.erase(it);
			return;
		}
	}
}
bool GameApplication::EntityExists( Entity* entity )
{
	for (Entity::Map_t::iterator it = m_entities.begin(); it != m_entities.end(); ++it)
	{
		if ((Entity*)(it->second) == entity)
		{
			return true;
		}
	}
	return false;
}

// World
void GameApplication::CreateWorld( HashedString name )
{
	m_worlds.insert(Pathing::World::Pair_t(name, new Pathing::World()));
}
Pointer<Pathing::World> GameApplication::RetrieveWorld( HashedString name )
{
	Pointer<Pathing::World> world;
	Pathing::World::Map_t::iterator it = m_worlds.find(name);
	if (it != m_worlds.end())
		world = it->second;
	return world;
}

// Texture filenames **note: not very nice solution
void GameApplication::RegisterTexture( std::string filename )
{
	m_textureStrings.push_back(filename);
}

// Selectables
void GameApplication::RegisterSelectable( RigidBody* selectable )
{
	m_selectables->AddRigidBody(selectable);
}
void GameApplication::RemoveSelectable( RigidBody* selectable )
{
	m_selectables->RemoveRigidBody(selectable);
}
Entity* GameApplication::Select( int x, int y )
{
	Entity* entity = 0;
	Maths::Vector3D from;
	Maths::Vector3D to;

	m_mainCamera->Unproject(x, y, from, to);

	if (m_selectables->RayCast(from, to, (void**)&entity))
	{
		return entity;
	}
	return 0;
}
Entity* GameApplication::Select( int x, int y, Maths::Vector3D& point )
{
	Entity* entity = 0;
	Maths::Vector3D from;
	Maths::Vector3D to;

	m_mainCamera->Unproject(x, y, from, to);

	if (m_selectables->RayCastGetPoint(from, to, (void**)&entity, point))
		return entity;
	return 0;
}

// Controllers
void GameApplication::RegisterController( Pointer<IEntityController> controller )
{
	m_controllers.push_back(controller);
}
void GameApplication::RemoveController( IEntityController* controller )
{
	for (IEntityController::Vector_t::iterator it = m_controllers.begin(); it != m_controllers.end(); ++it)
	{
		if ((IEntityController*)(*it) == controller)
		{
			UpdateTask::getSingleton().RemoveUpdateable(*it);
			m_controllers.erase(it);
			break;
		}
	}
}
void GameApplication::RemoveController( Entity* entity )
{
	for (IEntityController::Vector_t::iterator it = m_controllers.begin(); it != m_controllers.end(); ++it)
	{
		if ((*it)->getEntity() == entity)
		{
			UpdateTask::getSingleton().RemoveUpdateable(*it);
			m_controllers.erase(it);
			break;
		}
	}
}

// System functions - avoid use
Entity::Map_t& GameApplication::_getAllEntities()
{
	return m_entities;
}
Pointer<System>& GameApplication::_getSelectables()
{
	return m_selectables;
}
std::vector<std::string>& GameApplication::_getTextureStrings()
{
	return m_textureStrings;
}
IEntityController::Vector_t& GameApplication::_getControllers()
{
	return m_controllers;
}
Pathing::World::Map_t& GameApplication::_getWorlds()
{
	return m_worlds;
}
Pointer<CameraNode>& GameApplication::_getMainCamera()
{
	return m_mainCamera;
}
